<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
    </style>
</head>
<body>
<canvas id="canvas"></canvas>
<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    attribute vec2 a_Pin;
    uniform mat4 u_PvMatrix;
    uniform mat4 u_ModelMatrix;
    varying vec2 v_Pin;
    void main() {
        gl_Position = u_PvMatrix * u_ModelMatrix * a_Position;
        v_Pin=a_Pin;
    }

</script>
<script id="fragmentShader" type="x-shader/x-fragment">
    precision mediump float;
    uniform sampler2D u_Sampler;
    varying vec2 v_Pin;
    void main() {
        gl_FragColor=texture2D(u_Sampler,v_Pin);
    }

</script>
<script type="module">
    import {createProgram} from './js/utils.js'
    import {Matrix4, PerspectiveCamera, Vector3, Quaternion} from 'https://unpkg.com/three/build/three.module.js';
    import {Scene, Obj3D, Geo, Mat, OrbitControls} from './jsm/Webgl.js'

    const canvas = document.getElementById('canvas')
    canvas.width = window.innerWidth;
    canvas.height = window.innerHeight;

    const gl = canvas.getContext('webgl')
    const vertexShader = document.getElementById('vertexShader').innerText
    const fragmentShader = document.getElementById('fragmentShader').innerText

    const program  = createProgram(gl, vertexShader, fragmentShader)

    gl.clearColor(0, 0, 0, 1)
    gl.clear(gl.COLOR_BUFFER_BIT)

    // 多边形剔除功能
    gl.enable(gl.CULL_FACE);
    // 用来开启更新深度缓冲区的功能，也就是，如果通过比较后深度值发生变化了，
    // 会进行更新深度缓冲区的操作。启动它，OpenGL就可以跟踪再Z轴上的像素，这样，它只会再那个像素前方没有东西时，才会绘画这个像素。
    gl.enable(gl.DEPTH_TEST);

    // 透视相机
    const eye = new Vector3(2, 3, 5)
    const target = new Vector3(0, 0, 0)
    const up = new Vector3(0, 1, 0)

    const [fov, aspect, near, far] = [
        45,
        canvas.width / canvas.height,
        1,
        20
    ]

    const camera = new PerspectiveCamera(fov, aspect, near, far)
    camera.position.copy(eye)

    // 实例化轨道控制器
    const orbit = new OrbitControls({
        camera, target,
        dom: canvas,
    })

    orbit.update()

    /* 取消右击菜单的显示 */
    canvas.addEventListener('contextmenu', event => {
        event.preventDefault()
    })
    /* 指针按下时，设置拖拽起始位，获取轨道控制器状态。 */
    canvas.addEventListener('pointerdown', event => {
        orbit.pointerdown(event)
    })
    /* 指针移动时，若控制器处于平移状态，平移相机；若控制器处于旋转状态，旋转相机。 */
    canvas.addEventListener('pointermove', event => {
        orbit.pointermove(event)
    })
    /* 指针抬起 */
    canvas.addEventListener('pointerup', event => {
        orbit.pointerup(event)
    })
    /* 滚轮事件 */
    canvas.addEventListener('wheel', event => {
        orbit.wheel(event)
    })

    const scene = new Scene({ gl })

    let mat = null;
    let geo = null;

    const image = new Image()
    image.src = './images/mf.jpg'

    image.onload = function () {
        mat = new Mat({
            program,
            data: {
                u_PvMatrix: {
                    value: orbit.getPvMatrix().elements,
                    type: 'uniformMatrix4fv',
                },
                u_ModelMatrix: {
                    value: new Matrix4().elements,
                    type: 'uniformMatrix4fv',
                },
            },
            maps:{
                u_Sampler: {
                    image,
                    format: gl.RGBA,
                    minFilter: gl.LINEAR,
                },
            }
        })

//    v6----- v5
//   /|      /|
//  v1------v0|
//  | |     | |
//  | |v7---|-|v4
//  |/      |/
//  v2------v3

        geo = new Geo({
           data:{
               a_Position: {
                   array: new Float32Array([


                       -0.5, -0.5, -0.5,
                       -0.5, 0.5, -0.5,
                       0.5, -0.5, -0.5,
                       -0.5, 0.5, -0.5,
                       0.5, 0.5, -0.5,
                       0.5, -0.5, -0.5,

                       -0.5, -0.5, 0.5,
                       0.5, -0.5, 0.5,
                       -0.5, 0.5, 0.5,
                       -0.5, 0.5, 0.5,
                       0.5, -0.5, 0.5,
                       0.5, 0.5, 0.5,

                       -0.5, 0.5, -0.5,
                       -0.5, 0.5, 0.5,
                       0.5, 0.5, -0.5,
                       -0.5, 0.5, 0.5,
                       0.5, 0.5, 0.5,
                       0.5, 0.5, -0.5,

                       -0.5, -0.5, -0.5,
                       0.5, -0.5, -0.5,
                       -0.5, -0.5, 0.5,
                       -0.5, -0.5, 0.5,
                       0.5, -0.5, -0.5,
                       0.5, -0.5, 0.5,

                       -0.5, -0.5, -0.5,
                       -0.5, -0.5, 0.5,
                       -0.5, 0.5, -0.5,
                       -0.5, -0.5, 0.5,
                       -0.5, 0.5, 0.5,
                       -0.5, 0.5, -0.5,

                       0.5, -0.5, -0.5,
                       0.5, 0.5, -0.5,
                       0.5, -0.5, 0.5,
                       0.5, -0.5, 0.5,
                       0.5, 0.5, -0.5,
                       0.5, 0.5, 0.5,
                   ]),
                   size: 3
               },
               a_Pin: {
                   array: new Float32Array([
                       0, 0,
                       0, 0.5,
                       0.25, 0,
                       0, 0.5,
                       0.25, 0.5,
                       0.25, 0,

                       0.25, 0,
                       0.5, 0,
                       0.25, 0.5,
                       0.25, 0.5,
                       0.5, 0,
                       0.5, 0.5,

                       0.5, 0,
                       0.5, 0.5,
                       0.75, 0,
                       0.5, 0.5,
                       0.75, 0.5,
                       0.75, 0,

                       0, 0.5,
                       0.25, 0.5,
                       0, 1,
                       0, 1,
                       0.25, 0.5,
                       0.25, 1,

                       0.25, 0.5,
                       0.25, 1,
                       0.5, 0.5,
                       0.25, 1,
                       0.5, 1,
                       0.5, 0.5,

                       0.5, 0.5,
                       0.75, 0.5,
                       0.5, 1,
                       0.5, 1,
                       0.75, 0.5,
                       0.75, 1,
                   ]),
                   size: 2
               }
           }
        })

        const obj = new Obj3D({ geo, mat })

        scene.add(obj)

        !(function ani() {
            scene.setUniform(
                'u_PvMatrix',
                orbit.getPvMatrix().elements
            )
            scene.draw()
            requestAnimationFrame(ani)
        })()
    }
</script>
</body>
</html>
